/*******************************************************************************
 * Copyright:   Copyright (c) 2007. Hisilicon Technologies, CO., LTD.
 * Version:     V300R001B831
 * Filename:    HFKey.cpp
 * Description: This module deal with HF button
 * History:
                1.Created by SunShaojie on 2008/07/15
*******************************************************************************/

#ifdef DRV_ENABLE_HF_KEY

#include <windows.h>
#include <windev.h>
#include <winuser.h>
#include <winbase.h>
#include <winuserm.h>
#include <Nkintr.h>
#include <keybddbg.h>
#include <phone.h>
#include <pm.h>

#include "option.h"
#include "hisi6810_gpio.h"
#include "kpdCntl.h"
#include "Keypad.h"

#define HF_GPIO     GPIO_12_3

#define VOICE_RECOGNICE_PROC    TEXT("\\Program Files\\Cyberon\\VoiceCommander\\VoiceCommander.exe")

#define SIZEOFARRAY(a)  (sizeof(a) / sizeof(a[0]))

BOOL    g_bTimeElased = FALSE;

//-------------------------------------------------------------------------------
//
// Function: IsHfPowerKeyDown
//
// The Function checks that HF button is really pressed.
//
// Parameters:
//     None.
//
// Returns:
//     TRUE indicates success, FALSE indicates failure.
//
//-------------------------------------------------------------------------------
BOOL IsHfPowerKeyDown(void)
{
    UINT32  ulUpLvlNum=0, ulDownLvlNum=0;

    while((ulUpLvlNum<3) && (ulDownLvlNum<3))
    {
        if(EGPIO_DATA_HIGH == GpioGetValue(HF_GPIO))
        {
            ulUpLvlNum++;
            ulDownLvlNum=0;
        }
        else
        {
            ulDownLvlNum++;
            ulUpLvlNum=0;
        }

        Sleep(15);
    }

    if (ulUpLvlNum>=3)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

//-------------------------------------------------------------------------------
//
// Function: IsHfPowerKeyUp
//
// The Function checks that HF button is really released.
//
// Parameters:
//     None.
//
// Returns:
//     TRUE indicates success, FALSE indicates failure.
//
//-------------------------------------------------------------------------------
BOOL IsHfPowerKeyUp(void)
{
    UINT32  ulUpLvlNum=0, ulDownLvlNum=0;

    while((ulUpLvlNum<3) && (ulDownLvlNum<3))
    {
        if(EGPIO_DATA_LOW == GpioGetValue(HF_GPIO))
        {
            ulUpLvlNum++;
            ulDownLvlNum=0;
        }
        else
        {
            ulDownLvlNum++;
            ulUpLvlNum=0;
        }

        Sleep(10);
    }

    if (ulUpLvlNum>=3)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

//-------------------------------------------------------------------------------
//
// Function: ChangeToPowerOnState
//
// The Function set system state back to "on" state.
//
// Parameters:
//     None.
//
// Returns:
//     None.
//
//-------------------------------------------------------------------------------
VOID ChangeToPowerOnState(VOID)
{
    DWORD dwPwrFlags;
    TCHAR szPowerState[MAX_PATH];

    // Back to "on" state if we are not in "on" state.
    GetSystemPowerState(szPowerState,SIZEOFARRAY(szPowerState),&dwPwrFlags);

    //if((wcscmp(szPowerState,L"unattended")==0) || (wcscmp(szPowerState,L"screenoff")==0))
    if(POWER_STATE_ON != POWER_STATE(dwPwrFlags))
    {
        // We are not in power on state.
        SetSystemPowerState(NULL,POWER_STATE_ON,POWER_FORCE);
    }
}

//-------------------------------------------------------------------------------
//
// Function: ProcessTimeElapse
//
// The Function is called when time elapsed.
//
// Parameters:
//     uTimerID
//         [in] Timer ID.
//     uMsg
//         [in] Message ID.
//     dwUser
//         [in] User ID.
//     dw1
//         [in] parameter 1.
//     dw2
//         [in] parameter 2.
//
// Returns:
//     TRUE indicates success, FALSE indicates failure.
//
//-------------------------------------------------------------------------------
LPTIMECALLBACK ProcessTimeElapse(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
    PKEYPAD_DEVICE pDevice = (PKEYPAD_DEVICE)dwUser;
    g_bTimeElased = TRUE;

    ChangeToPowerOnState();
    if(FALSE == pDevice->sKpdCntl.bInCall)
    {
        BOOL    bRet;
        PROCESS_INFORMATION pi;

        // Send Recognise event
        //Call shutdown process
        bRet = CreateProcess(VOICE_RECOGNICE_PROC, NULL,
                             NULL,NULL,FALSE,0,NULL,NULL,NULL, &pi);
        if (FALSE != bRet)
        {
            CloseHandle (pi.hProcess);
            CloseHandle (pi.hThread);
        }
        RETAILMSG(1, (TEXT("HFKeyThreadProc: Send Recognise event\r\n")));
    }
    else
    {
        keybd_event(VK_TEND, 0, 0, 0);
        keybd_event(VK_TEND, 0, KEYEVENTF_KEYUP, 0);
    }

    return 0;
}

//-------------------------------------------------------------------------------
//
// Function: RedialPreviousDialedNumber
//
// The Function dial last number.
//
// Parameters:
//     None.
//
// Returns:
//     None.
//
//-------------------------------------------------------------------------------
VOID RedialPreviousDialedNumber()
{
    HANDLE  hCallLogDB = NULL;
    CALLLOGENTRY sCallLog;
    HRESULT hr = S_OK;
    DWORD   dwCount;

    if(S_OK == PhoneOpenCallLog(&hCallLogDB))
    {
        if(NULL == hCallLogDB)
        {
            return;
        }

        if(S_OK == PhoneSeekCallLog(hCallLogDB, CALLLOGSEEK_BEGINNING, 0, &dwCount))
        {
            do
            {
                ZeroMemory(&sCallLog, sizeof(CALLLOGENTRY));
                sCallLog.cbSize = sizeof(CALLLOGENTRY);

                hr = PhoneGetCallLogEntry (hCallLogDB, &sCallLog);

                if( hr == S_OK )
                {
                    // find outgoing call
                    if(IOM_OUTGOING == sCallLog.iom)
                    {
                        PHONEMAKECALLINFO phCallInfo;

                        ZeroMemory(&phCallInfo, sizeof(PHONEMAKECALLINFO));
                        phCallInfo.cbSize  = sizeof(PHONEMAKECALLINFO);
                        phCallInfo.dwFlags = PMCF_DEFAULT;

                        phCallInfo.pszDestAddress = sCallLog.pszNumber;

                        PhoneMakeCall(&phCallInfo);


                        LocalFree(sCallLog.pszName);
                        LocalFree(sCallLog.pszNameType);
                        LocalFree(sCallLog.pszNote);
                        LocalFree(sCallLog.pszNumber);

                        return;
                    }
                }

                // Free non-null strings returned by PhoneGetCallLogEntry
                LocalFree(sCallLog.pszName);
                LocalFree(sCallLog.pszNameType);
                LocalFree(sCallLog.pszNote);
                LocalFree(sCallLog.pszNumber);

            }while( S_OK == hr );
        }
    }

    return;
}

//-----------------------------------------------------------------------------
//
// Function: HFKeyThreadProc
//
// This function initialize the keypad Backlight light event.
//
// Parameters:
//     pContext
//         [in] Long pointer to a single 32-bit parameter value passed to the thread.
//
// Returns:
//     0 indicates Thread is finished.
//
//-----------------------------------------------------------------------------
DWORD HFKeyThreadProc(VOID *pContext)
{
    PKEYPAD_DEVICE pDevice = (PKEYPAD_DEVICE)pContext;
    static BOOL bHfKeyIsDown = FALSE;
    static MMRESULT dwTimerObj = 0;
    USP_GPIO_INT_MODE gpioIntrMode = {HF_GPIO, EGPIO_INT_EDGE, EGPIO_INT_SINGLE, EGPIO_INT_UP_HIGH};

    while(!IsAPIReady(SH_SHELL) || !IsAPIReady(SH_WMGR) || !IsAPIReady(SH_GDI))
    {
        Sleep(300);
    }

    RETAILMSG(ZONE_PDD|ZONE_FUNCTION, (TEXT("HFKeyThreadProc:\r\n")));
    while (TRUE)
    {
        WaitForSingleObject(pDevice->sHfKey.hHfkeyEvent, INFINITE);
        RETAILMSG(ZONE_PDD|ZONE_FUNCTION, (TEXT("HFKeyThreadProc: ButtonEvent Button\r\n")));

        if (bHfKeyIsDown)
        {
            if(IsHfPowerKeyUp())
            {
                gpioIntrMode.sense = EGPIO_INT_EDGE;
                gpioIntrMode.event = EGPIO_INT_UP_HIGH;
                GpioSetIntrMode(&gpioIntrMode);
                if(FALSE == g_bTimeElased)
                {
                    timeKillEvent(dwTimerObj);

                    pDevice->sHfKey.dwHfPressStat++;
                    if(pDevice->sKpdCntl.bInCall)  //Incall
                    {
                        //Send keypress
                        RETAILMSG(1, (TEXT("HFKeyThreadProc: Send Talk Key Down\r\n")));
                        ChangeToPowerOnState();
                        keybd_event(VK_TTALK, 0, 0, 0);
                        keybd_event(VK_TTALK, 0, KEYEVENTF_KEYUP, 0);
                        pDevice->sHfKey.dwHfPressStat = HF_KEY_NONE_PRESS;
                        pDevice->sHfKey.dwHfKeyValue = HF_KEY_VALUE_TALK;
                    }
                    else if(HF_KEY_FIRST_PRESS == pDevice->sHfKey.dwHfPressStat)
                    {
                        pDevice->sHfKey.dwHfKeyValue = HF_KEY_VALUE_NONE;
                        pDevice->sHfKey.dwHfBgnTick = GetTickCount();
                    }
                    else if(HF_KEY_SECOND_PRESS == pDevice->sHfKey.dwHfPressStat)
                    {
                        DWORD   dwTick = GetTickCount();
                        if((dwTick - pDevice->sHfKey.dwHfBgnTick) < 1000)
                        {
                            //Send Message to call last one
                            RETAILMSG(1, (TEXT("HFKeyThreadProc: Send Talk Key Call Again\r\n")));
                            //keybd_event(VK_TTALK, 0, 0, 0);
                            //keybd_event(VK_TTALK, 0, KEYEVENTF_KEYUP, 0);
                            //Sleep(5);
                            //keybd_event(VK_TTALK, 0, 0, 0);
                            ChangeToPowerOnState();
                            RedialPreviousDialedNumber();
                            pDevice->sHfKey.dwHfPressStat = HF_KEY_NONE_PRESS;
                            pDevice->sHfKey.dwHfKeyValue = HF_KEY_VALUE_CALLAGAIN;
                        }
                        else
                        {
                            pDevice->sHfKey.dwHfBgnTick = dwTick;
                            pDevice->sHfKey.dwHfPressStat = HF_KEY_FIRST_PRESS;
                            pDevice->sHfKey.dwHfKeyValue = HF_KEY_VALUE_NONE;
                        }
                    }
                }
                else
                {
                    pDevice->sHfKey.dwHfKeyValue = HF_KEY_VALUE_RECOGNISE;
                    pDevice->sHfKey.dwHfPressStat = HF_KEY_NONE_PRESS;
                }

                //keybd_event(HF_KEY, 0, KEYEVENTF_KEYUP, 0);
                bHfKeyIsDown = FALSE;
                RETAILMSG(1, (TEXT("HFKeyThreadProc: HF Up\r\n")));
            }
        }
        else
        {
            if(FALSE != pDevice->sHfKey.bHfKeyEnable)
            {
                if(IsHfPowerKeyDown())
                {
                    if(FALSE != pDevice->sHfKey.bHfKeyEnable)
                    {
                        g_bTimeElased = FALSE;
                        //NKDbgPrintfW(TEXT("HFKeyThreadProc: has a HF key.\r\n"));
                        dwTimerObj = timeSetEvent(1000, 100, (LPTIMECALLBACK)ProcessTimeElapse, (DWORD)pDevice, TIME_ONESHOT|TIME_CALLBACK_FUNCTION);

                        //keybd_event(HF_KEY, 0, 0, 0);
                        bHfKeyIsDown = TRUE;
                        gpioIntrMode.sense = EGPIO_INT_LEVEL;
                        gpioIntrMode.event = EGPIO_INT_DOWN_LOW;
                        GpioSetIntrMode(&gpioIntrMode);
                        RETAILMSG(1, (TEXT("HFKeyThreadProc: HF Down\r\n")));
                    }
                }
            }
        }

        //RETAILMSG(1, (TEXT("PWB: Power Button is Key Up\r\n")));
        InterruptDone(pDevice->sHfKey.dwHfSysIntr);
    }

    return 0;
}

//-------------------------------------------------------------------------------
//
// Function: HFKeyThreadEnd
//
// The Function end HF button control thread.
//
// Parameters:
//     pDevice
//         [in] key device infomation.
//
// Returns:
//     None.
//
//-------------------------------------------------------------------------------
VOID HFKeyThreadEnd(PKEYPAD_DEVICE pDevice)
{
    RETAILMSG(ZONE_PDD|ZONE_FUNCTION, (TEXT("HFKeyThreadEnd  +\r\n")));

    if(pDevice->sHfKey.hHfkeyEvent)
    {
        //SetEvent(pDevice->sHfKey.hHfkeyEvent);
        CloseHandle(pDevice->sHfKey.hHfkeyEvent);
    }

    InterruptDisable(pDevice->sHfKey.dwHfSysIntr);
    KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &(pDevice->sHfKey.dwHfSysIntr), sizeof(DWORD), NULL, 0, NULL);

    //if(pDevice->sHfKey.hHfkeyThread)
    //{
    //    CloseHandle(pDevice->sHfKey.hHfkeyThread);
    //    pDevice->sHfKey.hHfkeyThread=NULL;
    //}

    RETAILMSG(ZONE_PDD|ZONE_FUNCTION, (TEXT("HFKeyThreadEnd  -\r\n")));
}


//-----------------------------------------------------------------------------
//
// Function: KppBklThreadStart
//
// This function start HF button control thread.
//
// Parameters:
//     pDevice
//         [in] key device infomation.
//
// Returns:
//     TRUE indicates success. FALSE indicates failure.
//
//-----------------------------------------------------------------------------
BOOL HFKeyThreadStart(PKEYPAD_DEVICE pDevice)
{
    BOOL result;
    DWORD extwake_irq[3] = {(DWORD)-1, 0x8, HF_GPIO};
    USP_GPIO_INT_MODE gpioIntrMode =
            {HF_GPIO, EGPIO_INT_EDGE, EGPIO_INT_DOUBLE, EGPIO_INT_UP_HIGH};

    RETAILMSG(ZONE_INIT|ZONE_FUNCTION, (TEXT("HfInit: Init pContext: %x.\r\n"), pDevice));

    pDevice->sHfKey.hHfkeyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == pDevice->sHfKey.hHfkeyEvent)
    {
        //RETAILMSG(ZONE_ERROR, (TEXT("HFKeyThreadStart: Failed to create Interupt Event\r\n")));
        NKDbgPrintfW(TEXT("[Error Keypad]HFKeyThreadStart: Failed to create Interupt Event!\r\n"));
        goto CleanUp;
    }

    // set Power GPIO input
    result = GpioSetDirection(HF_GPIO, EGPIO_DIR_INPUT);
    if(!result)
    {
        //RETAILMSG(ZONE_ERROR, (TEXT("HFKeyThreadStart: Set PWR Gpio Direction Input Failure\r\n")));
        NKDbgPrintfW(TEXT("[Error Keypad]HFKeyThreadStart: Set PWR Gpio Direction Input Failure!\r\n"));
        goto CleanUp;
    }

    // set gpio trigger mode
    result = GpioSetIntrMode(&gpioIntrMode);
    if(!result)
    {
        //RETAILMSG(ZONE_ERROR, (TEXT("HFKeyThreadStart: Set PWR Gpio interrupt mode Failure\r\n")));
        NKDbgPrintfW(TEXT("[Error Keypad]HFKeyThreadStart: Set PWR Gpio interrupt mode Failure!\r\n"));
        goto CleanUp;
    }

    // Request the SYSINTR for the power button.
    result = KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, extwake_irq, sizeof(extwake_irq), &(pDevice->sHfKey.dwHfSysIntr), sizeof(UINT32), NULL);
    if(!result)
    {
        //RETAILMSG(ZONE_ERROR, (TEXT("HFKeyThreadStart: Failed to request SYSINTR\r\n")));
        NKDbgPrintfW(TEXT("[Error Keypad]HFKeyThreadStart: Failed to request SYSINTR!\r\n"));
        goto CleanUp;
    }
    RETAILMSG(ZONE_INIT|ZONE_FUNCTION, (TEXT("HFKeyThreadStart: get sysint: phyIntr: %d, sysIntr: %d\r\n"), extwake_irq[2], pDevice->sHfKey.dwHfSysIntr));

    result = InterruptInitialize(pDevice->sHfKey.dwHfSysIntr, pDevice->sHfKey.hHfkeyEvent, NULL, 0);    // will unmask EXTWAK 0 IRQ
    if(!result)
    {
        //RETAILMSG(ZONE_ERROR, (TEXT("HfInit:InterruptInitialize() failed\r\n")));
        NKDbgPrintfW(TEXT("[Error Keypad]HFKeyThreadStart: InterruptInitialize failed!\r\n"));
        goto CleanUp;
    }

    RETAILMSG(ZONE_PDD|ZONE_FUNCTION,(TEXT("HF key Thread Start:\r\n")));
    // Create keypad backlight control thread
    pDevice->sHfKey.hHfkeyThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)HFKeyThreadProc,pDevice,0,NULL);
    if (NULL == pDevice->sHfKey.hHfkeyThread)
    {
        //RETAILMSG(ZONE_ERROR, (TEXT("HFKeyThreadStart: CreateThread failed\r\n")));
        NKDbgPrintfW(TEXT("[Error Keypad]HFKeyThreadStart: CreateThread failed!\r\n"));
        goto CleanUp;
    }
    return TRUE;

CleanUp:
    HFKeyThreadEnd(pDevice);
    return FALSE;
}

VOID HFKeyInit(PKEYPAD_HFKey pHfKey)
{
    pHfKey->hHfkeyThread = NULL;
    pHfKey->hHfkeyEvent = NULL;
    pHfKey->dwHfSysIntr = (DWORD)-1;
    pHfKey->dwHfBgnTick = 0;
    pHfKey->dwHfPressStat = HF_KEY_NONE_PRESS;
    pHfKey->dwHfKeyValue = HF_KEY_VALUE_NONE;
}

#endif
